This XFCN was actually written after a conversation at the Boston Mac Expo in which a gentleman who shall remain nameless almost convinced me that it was impossible to write a reasonable HyperCard external which would allow the user to install an additional Pull-Down, Tear-Off menu like the "Tools" menu, but one in which the user could customize the selections and have them do anything he/she wanted.
I then decided to undertake the challenge, and have been working on it ever since. The result is here before you, something in between a kludgey workaround and a nice addition to HyperTalk. As in the "Tools" menu, the little tool icons are actually font characters which you can change into anything you wish using ResEdit or a Font Editor. Then you can write HyperTalk scripts to define what each of the 18 selections will do. The menu can be pulled down, torn off, hidden, and shown exactly like the "Tools" (or "Pattern") menu. There are additional features explained later, which the "Tools" menu does not have.
WARNING • WARNING • WARNING
This Is a Beta Version
••• PLEASE READ ALL DOCUMENTATION BEFORE USING THE PALETTE XFCN IN YOUR OWN STACKS •••
It may do a few things which will surprise you, not always pleasantly.
You will be doing yourself a favor while learning to use the Palette XFCN if you read this section carefully, because once you understand the underlying "mechanics" of it all then the necessary scripting makes much more sense.
•••••
Let's break the Palette XFCN down into two components, 1) the Pull-Down Menu, and 2) the "torn off" box menu or "Palette" which you can drag around the screen.
•••••
We will consider the Pull-Down Menu first. When you call Palette from HyperTalk it will install a menu of any name you choose in the menu bar. When you pull it down you will see a menu like the "Tools" menu only with some unusual "tools" in it. These "tools" are actually the characters A-R in a special font called ExtToolsΔí which resides in the stack's resource fork. You may edit these characters with ResEdit or a font editor to make them into any "tools" of your choice. In fact you may create and use a whole new font if you wish. Palette allows you this fexibility.
In spite of the APPEARANCE of these characters (dingbats), they are still seen by HyperCard as the characters A-R, and can be accessed by the doMenu command. For example 'doMenu "A"' will cause the first tool to do it's thing.
It is essentially through this method that we define each "tool's" function. We need a script in either the background or the stack which intercepts menu selections, checks for A-R, and carries them out if it finds them. This script looks like this (I'll explain the "S" at the beginning in a minute):
on doMenu which
if which is "S" then
-- script of your choice
else
if which is "A" then
-- script of your choice
else
if which is "B" then
-- script of your choice
else
if which is "C" then
-- script of your choice
else
if which is "D" then
-- script of your choice
else
if which is "E" then
-- script of your choice
else
if which is "F" then
-- script of your choice
else
if which is "G" then
-- script of your choice
else
if which is "H" then
-- script of your choice
else
if which is "I" then
-- script of your choice
else
if which is "J" then
-- script of your choice
else
if which is "K" then
-- script of your choice
else
if which is "L" then
-- script of your choice
else
if which is "M" then
-- script of your choice
else
if which is "N" then
-- script of your choice
else
if which is "O" then
-- script of your choice
else
if which is "P" then
-- script of your choice
else
if which is "Q" then
-- script of your choice
else
if which is "R" then
-- script of your choice
else
pass doMenu
end if
end if
end if
end if
end if
end if
end if
end if
end if
end if
end if
end if
end if
end if
end if
end if
end if
end if
end if
end doMenu
Easy enough, although it takes up a lot of space and can look complicated. It's often easiest to define a separate function or procedure for each Menu Item and then just call it from the above structure. Now to be sure it's clear, if the user clicks on the first (upper left corner) menu item (or tool) the menu item is read by HyperCard as "A" and we use the above handler to intercept it and carry out some function of our own choosing.
•••••
Now for the second half, the Palette itself, i.e., the torn-off menu/box. The Palette XFCN creates a modeless (means you can still do other things while it is hanging around) dialog box shaped just like the pull-down menu. Now this box exists, but is hidden, as soon as you call the Palette XFCN from HyperTalk. Just as with the "Tools" menu, if you pull down the "Palette" menu and then pull it further you get a gray box which follows the cursor around. When you let go of the mouse, the Palette appears where the gray box was, just like the "Tools" menu. Only one detail with the Palette XFCN, we have to make this happen. When we let go of the mouse with the gray box visible the menu returns the character "S", that's one letter after "R" which is the last menu item. You could also think of it as standing for "Show Menu." This is the reason for the "S" in the first part of the above "doMenu" handler. We'll learn more specifics later.
If you are still reading this it is clear that you are a real HyperCard aficionado, and you have already undoubtedly asked yourself the question "How do the palette, the pull down menu, and HyperCard keep one another informed about what's going on?" The answer is through the following "idle" handler:
on idle
global pickedOne
put Palette("Update") into temp
if pickedOne is not empty then doMenu pickedOne
put empty into pickedOne
pass idle
end idle
This keeps the whole structure together and without it Palette will not function. In fact, if you leave out the idle handler, you will notice a few strange things, like your menu flash will be set to zero until you leave the stack. Another important aspect of the idle handler is the global variable "pickedOne." It is this variable, as you can see, which transmits the item picked on the palette to the doMenu handler. This global must be named "pickedOne" because that's what the Palette XFCN looks for. By the way, if you keep getting a dialog box of some kind which comes up on the screen repeatedly, with about the frequency of the idle message, this probably means "pickedOne" has some non-menu item value in it
(usually because you forgot to define a menu item). To stop the recurring dialog box, type "put empty into pickedOne" into the message box.
•••••
So, there are really only two handlers necessary to implement Palette once it is installed, the doMenu handler and the idle handler. Please continue exploring this stack to learn about many other features, the details of installation, and how Palette might actually be useful.
There is a 'FONT' resource along with its associated 'FOND' resource in the resource fork of the stack, and the family has an id of 145. The FONT is named "ExtToolsΔí" and it contains the characters "A" through
"R", i.e., ASCII 65-82. If you take a look at this font with ResEdit, you will see that the characters do not look like A-R, but rather more like a peculiar set of icon-like characters, or DingBats to be more precise. I have provided a set of these "tools" many of which you will recognize from various HyperCard nooks and crannies. PLEASE, do not feel as though you have to use THESE. The whole reason for including the "tools" as a FONT resource is so that you are able to create your own. You do this by editing the existing tools using the font edit mode of ResEdit (or using a stand alone Font Editor).
In fact, if you like, you may create your own "tools" font and name it anything you wish (with your own ID number), and you may have more than one if your stack requires a different Palette in different places. The only limitation here is that you may only have one Palette installed at any given moment.
In just a bit, we will get into how to let the Palette XFCN know which font you wish to use, but probably the easiest route is to copy the FONT & FOND from this stack into yours, and then edit the characters, i.e.,
"tools" to turn them into whatever you need in your stack (of course, you will also have to write their scripts in the stack, or else they won't do anything).
Don't panic when you catch a glimpse of the Palette XFCN stack's resource fork using ResEdit, ResCopy, or a similar utility. There will appear to be many resources, but we shall make sense of all of them right here.
•••••
First, we will look at the resources which are essential to running the XFCN. Without the following resources, the Palette XFCN will not run, but it will inform you of the missing resource(s). You must have:
XFCN "Palette" ID = 1819
MDEF "PaletteMDEF" ID = 298
DLOG "Palette" ID = 8491
DITL "Palette" ID = 4028
As you might imagine, the XFCN is the meat of the thing, the MDEF is a definition procedure for the pull-down menu, and the DLOG & DITL are the definitions of the Palette box (torn off).
•••••
Now if you run the Palette XFCN with just the above resources, you will see a very bland box with the letters A-R in the little squares, and they will be in the system font. Not very exciting. For this reason, you will also wish to include a "tools" font. The one I have included with the stack (which you may edit in your own stacks) is:
FOND "ExtToolsΔí" ID = 145
FONT "ExtToolsΔí" ID = 18560
If you use ResCopy instead of ResEdit you will also see:
FONT ID = 18572
Copy this one into your stack also.
•••••
Well, that's it for necessary resources. You will notice several other resources, but these are all just there to make the stack more pleasant to get through. There are several ICON's, my own little version of a ShutDown XCMD, and a variation on Flash which I named "Nukem." You don't need any of these, but you're welcome to put them to any use you wish, they are public domain freebies, such as they are.
We have spent a lot of time trying to become familiar with the Palette XFCN, and we have also focused somewhat on its limitations. Now we will focus on its features, which I hope will inspire people actually to use it in appropriate stacks.
•••••
The Palette XFCN has 10 modes, as follows (the first step is the hard one):
•••••
1) Install:
This mode is used to install the Palette into the MenuBar and to create the Palette (initially invisible). None of the other modes does anything until the Palette is "Installed." It takes 6 parameters. The first parameter in all modes must be the name of the mode, so in this case the first parameter is "Install." The second parameter should be the name you wish the new menu to have, such as "NewTools," or in the case of the demo here, "Palette." The third parameter is the name of the FONT you are using to define your "tools." In this stack, the FONT and hence the third parameter is "ExtToolsΔí."
Now parameters number 4, 5, and 6 require a bit of explanation. You see, each tool on the Palette menu can be represented by one of three kinds of buttons, and you will need to assign each button to one of these three types. The default type is just a plain button, i.e., you click on it and it blinks once, then it's off and running, doing its thing. The second type is more like you find in the "Tools" menu, and we'll call this a Radio button, i.e., when you click on an inactive one it is highlighted, and the previously highlighted button is "un-highlighted." These parameters will allow you to define which buttons you wish to include in the pool of radio type buttons (the top three in the demo). Finally, the third type of button is what I call a Toggle button, i.e., it can be either on or off, and a mouseClick toggles it to the opposite position. This type of button has its own special highlight in Palette, and you can define which buttons you wish to include in the pool of toggle type buttons. After that, you simply have to write the scripts for each of these items in the "doMenu" handler discussed earlier so that the buttons behave appropriately to their type.
So, with that said, here's how you use parameter's 4, 5, and 6. Parameter 4 is a text string containg the letter of each Palette button (A-R) which you want highlighted right from the start, as soon as the palette is installed. This obviously applies only to Radio and Toggle type buttons. You can only highlight one initial Radio type button, and you can highlight any or all of your toggle type buttons.
Parameter 5 is a text string containing the letters corresponding to the Palette buttons (or call them menu items, for the sake of precision) just as in parameter 4, except these are the ones you wish to define as Radio type buttons. Parameter 6 is the same thing, only these are the ones you wish to call Toggle type buttons.
Any letters you leave out will remain standard blink type buttons. In fact the whole Palette will be that way if you just pass three null strings, i.e., "", for parameters 4, 5, and 6.
Here is the script from the demo in this stack. It starts out with button "C" highlighted, defines buttons "ABC" as radio type, and none as Toggle type, thus leaving the remaining buttons standard.
put "C" into myState
put "ABC" into myRad
put "" into myTog
put Palette("Install","Palette","ExtToolsΔí",myState,myRad,myTog) into temp
One final word, the XFCN returns the decimal address of the MenuHandle, which you do not need, but which you might be vaguely interested in if you go in for such things. Whew...now the rest of the modes are simple...
•••••
2) Remove:
In contrast to "Install," removing the Palette is a piece of cake. "Remove" is the only parameter and it just removes the whole thing, i.e., the Palette, the Menu, and the hidden button. The sample script from the demo is:
put Palette("Remove") into temp
•••••
3) Update:
This is a key mode which is absolutely essential to the proper functioning of the Palette XFCN and it belongs in the "idle" handler as previously discussed. I won't get into all the housekeeping it does, but take my word for it, it's a lot. "Update" is the only parameter, but remember, the update mode will not work correctly, i.e., it will not connect the Palette with the menu, unless you include the global variable "pickedOne" in the handler as follows:
on idle
global pickedOne
put Palette ("Update") into temp
if pickedOne is not empty then doMenu pickedOne
put empty into pickedOne
pass idle
end idle
•••••
4) Show:
put Palette("Show") into temp
This just shows the torn off Palette wherever it happens to be. If you have just torn it off, it will be where you left the "gray box", but it will be invisible. Thus, use the "Show" mode in your doMenu handler when the menu item is "S." See the demo script for an example.
•••••
5) Hide:
put Palette("Hide") into temp
Puts the Palette away, but like the "Tools" palette, it is merely invisible, and a subsequent "Show" command will bring it back right where you left it.
•••••
6) Toggle:
Also only one parameter, "Toggle." This shows the Palette if it's invisible and hides it if it's visible. It is most useful for assigning a toggle key combination such as <ctrl>-tab as in the demo:
on controlKey which
if which is 9 then -- ASCII for TabKey
put Palette("Toggle") into temp
end if
pass controlKey
end controlKey
•••••
7) Query:
put Palette("Query") into message box
This will return three text strings, separated by commas (that is, it will return three items into the message box, each a text string). This will tell you the current state of the menu. The strings contain the letters (A-R) corresponding to the menu items (buttons) on the Palette. They are the same as in
"Install." The first string will contain the letters of all the highlighted buttons of all types, the second string tells you which buttons are Radio buttons, and the third string tells you which buttons are Toggle types. You will see that this is all the information you need.
•••••
8) Fill:
This is the opposite of Query, it lets you redefine the button types, or change the highlighting. It takes four parameters. The first is "Fill," and then it takes three strings identical to 4, 5, and 6 of the install mode. Here is a quick sample:
put Palette("Fill","B","ABC","DEF")
This script would take the existing Palette and Highlight the second item in the top row as requested by the first parameter. The entire top row become radio buttons as requested by the second parameter, and the second row will be toggle buttons as ordered by the third parameter. All the rest will be standard buttons.
•••••
9) Disable:
put Palette("Disable") into temp
This script, when called after Palette has been installed, will disable the torn off Palette so that only the pull-down menu works. That is, you won't be able to tear it off. This is useful if the user will be using some tool other than the browse tool. Since the torn off palette dosn't work outside the browse tool, you might want to limit access to the pull-down menu only which works in any tool.
•••••
10) Enable:
put Palette("Enable") into temp
This, as you might have guessed, restores the functioning of the torn off Palette after it has been disabled by the disable mode above.
•••••
I guess in the interest of completeness I should let you know that there is an 11th mode which takes the one parameter "Link." This is the mode that is used in the hidden background button named
This is obviously how the dialog box (since that is what the Palette is in reality) is linked to the stack and to mouse events inside its boundaries. Are you still with me? Wow, that's HyperCard dedication. Enough about Palette modes.
One thing's for sure, and that is that the Palette XFCN was a bear to write, and it has a few limitations. For example, card buttons can get in between the Palette and its button; also, a handler is operating when the mouse is inside the Palette, so it isn't truly modeless, i.e., you have to move the mouse out of the box for some actions to work, e.g., <ctrl>-tab, (also, the Palette itself only functions with the browse tool, although the menu always works). Further, it is a beta XFCN, and I have only been able to test it on my SE. Although it should work on other machines, I can't promise that it will. I can't promise that it will be compatible with future versions of HyperCard either since I have made use of my own undocumented
"discoveries" about HyperCard. Given these shortcomings, what good is the thing?
•••••
Well, first, it's just plain fun for any HyperCard nut and just seems like one of those things that's nice to be able to do in HyperCard.
Since that doesn't answer the question, how about this: The pull-down menu is not a kludge, and that is useful for all kinds of applications (using disable mode to get rid of the Palette itself).
The whole thing (including the Palette itself) is useful in stacks in which the Palette essentially contains all the buttons necessary to negotiate the stack. This allows the user to get around without cluttering up the cards with buttons.
This is a beta version of the Palette XFCN, and since I can make no guarantees about it, I certainly wouldn't dream of charging any money for it. It is freely distributed for use as you see fit, but please credit me in your stack if you use it.
The amount of effort I put into trying in future versions to iron out some of the limitations of Palette
(if this is even possible) will depend on the demand, so if you find the stack useful please let me know. And don't hesitate to send me samples of stacks in which you've used it.
For the other HyperCard and general Mac programming fanatics out there, I am open to suggestions on how to get rid of that hidden button and trap the Palette mouseDown events some other way. An idle handler alone is too slow, and it also quits in tools other than the browse tool. A trap patch to intercept HyperCard's GetNextEvent call might process the events, but still wouldn't leave me any way to communicate the results to HyperCard or the XFCN (not to mention, it isn't very nice). I doubt Bill will hand over HyperCard's source code, especially for this. So, I'm open to ideas, but I for one am fresh out, and sort of amazed that this thing actually works as well as it does. Good luck with it, and keep me posted on whether you all can make any use of it.